package ltd.hxya.novel.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ltd.hxya.novel.admin.entity.*;
import ltd.hxya.novel.admin.mapper.OperationMapper;
import ltd.hxya.novel.admin.mapper.UserMapper;
import ltd.hxya.novel.admin.service.*;
import ltd.hxya.novel.admin.vo.UserVo;
import ltd.hxya.novel.common.constant.ParamsConstant;
import ltd.hxya.novel.common.constant.redis.RedisConstant;
import ltd.hxya.novel.common.exception.NovelGlobalException;
import ltd.hxya.novel.common.utils.JwtUtils;
import ltd.hxya.novel.common.utils.PageUtils;
import ltd.hxya.novel.common.utils.RedisUtils;
import ltd.hxya.novel.common.bean.ResultEnum;
import ltd.hxya.novel.common.vo.PageParam;
import ltd.hxya.novel.springsecurity.entity.UserDetail;
import ltd.hxya.novel.springsecurity.utils.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author hty
 * @since 2022-10-03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private OperationMapper operationMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IOperationService operationService;

    @Autowired
    private IUserOperationService userOperationService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private OperationRoleService operationRoleService;

    @Autowired
    private UserRoleService userRoleService;

    @Override
    public User getUserByUsername(String username) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("user_name",username);
        User user = this.baseMapper.selectOne(userQueryWrapper);
        return user;
    }

    @Override
    public String login(User user) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (ObjectUtils.isEmpty(authenticate)){
            throw new NovelGlobalException(ResultEnum.ADMIN_LOGIN_ERROR.getCode(), ResultEnum.ADMIN_LOGIN_ERROR.getMsg());
        }
        UserDetail userDetail = (UserDetail) authenticate.getPrincipal();

        //TODO JWT生成token出现错误时给出相应的错误提示
        Integer userId = userDetail.getUser().getUserId();
        String token = JwtUtils.getToken(userId);

        redisUtils.save(RedisConstant.ADMIN_USER_KEY+userId,userDetail);


        return token;
    }

    /**
     * 查询当前登录的用户信息
     * @return
     */
    @Override
    public UserVo info() throws ExecutionException, InterruptedException {
        //从SecurityContextHolder 中取出信息
        UserDetail userDetail = SecurityUtils.principal();
        UserVo userVo = new UserVo();
        //查询用户信息，查询用户角色
        BeanUtils.copyProperties(userDetail.getUser(),userVo);
        Integer userId = userDetail.getUser().getUserId();
        //通过userId信息，查询角色和操作信息
        CompletableFuture<Role> roleCompletableFuture = CompletableFuture.supplyAsync(() -> roleService.roleByUserId(userId));

        //根据role获得所有的操作信息
        CompletableFuture<List<Operation>> operationCompletableFuture = CompletableFuture.supplyAsync(() -> operationService.operaByUserId(userId));

        CompletableFuture.allOf(roleCompletableFuture,operationCompletableFuture).get();

        //将信息添加到userVo中
        userVo.setRole(roleCompletableFuture.get());

        userVo.setOperation(operationCompletableFuture.get());

        return userVo;
    }

    @Override
    public Page<UserVo> grantedUser(UserVo userVo) {


        Page<UserVo> userVos= null;
        //取出roleIds
        Integer[] roleIds = userVo.getRoleIds();
        userVos =  userMapper.grantedUser(PageUtils.getPage(),userVo);

        if (userVos==null){
            //TODO 对数据为null的操作
        }
        return userVos;

    }

    @Override
    public Page<UserVo> ungrantedUser(UserVo userVo) {
        Page<UserVo> userVoPage = userMapper.ungrantedUser(PageUtils.getPage(),userVo);
        return userVoPage;
    }

    @Override
    public Page<Operation> noHasPermission(User user) {
        Integer userId = user.getUserId();

        Page<Operation> operationPage = operationMapper.noHasPermission(PageUtils.getPage(),userId);
        return operationPage;

    }

    @Override
    public void addPermission(UserOperation userOperation) {
        userOperationService.save(userOperation);
    }

    @Override
    public Page<Operation> hasPermission(Integer userId) {
        Page<Operation> operationPage = userMapper.getPagePermissionsByUserId(PageUtils.getPage(),userId);
        return operationPage;
    }

    @Override
    public void deletePermission(UserOperation userOperation) {
        QueryWrapper<UserOperation> userOperationQueryWrapper = new QueryWrapper<>();
        userOperationQueryWrapper.eq("user_id",userOperation.getUserId());
        userOperationQueryWrapper.eq("operation_id",userOperation.getOperationId());
        userOperationService.getBaseMapper().delete(userOperationQueryWrapper);
    }

    @Override
    public void disableAccount(User user) {
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        if (user.getUserId()!=null){
            userUpdateWrapper.eq("user_id",user.getUserId());
        }
        if (user.getStatus()!=null){
            userUpdateWrapper.set("status",user.getStatus());
        }
    }

    @Override
    public void logout() {
        UserDetail userDetail = SecurityUtils.principal();
        Integer userId = userDetail.getUser().getUserId();
        redisUtils.delete(RedisConstant.ADMIN_USER_KEY+userId);
    }


    // 管理员的管理，那就是对admin进行管理，所有查询出来的都是key为admin的
    @Override
    public Page<User> userList(User user) {
        //获取page信息
        PageParam pageParmas = PageUtils.getPageParams();
        //构造sql
        QueryWrapper<User> roleQueryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(user.getUserName())){
            roleQueryWrapper.eq("user_name",user.getUserName());
        }
        if (!StringUtils.isEmpty(user.getNickName())){
            roleQueryWrapper.eq("nick_name",user.getNickName());
        }
        if (!StringUtils.isEmpty(user.getStatus())){
            roleQueryWrapper.eq("status",user.getStatus());
        }
        Map<String, Object> params = user.getParams();
        if (!CollectionUtils.isEmpty(params)){
            String beginTime = (String) user.getParams().get(ParamsConstant.BEGIN_TIME);
            String endTime = (String) user.getParams().get(ParamsConstant.END_TIME);
            if (!StringUtils.isEmpty(endTime)){
                roleQueryWrapper.le("create_time",endTime);
            }
            if (!StringUtils.isEmpty(beginTime)){
                roleQueryWrapper.ge("create_time",beginTime);
            }
        }
        Page<User> userPage = this.page(new Page<User>(pageParmas.getCurrent(), pageParmas.getSize()), roleQueryWrapper);
        return userPage;
    }

    /**
     * 添加管理员的处理
     * @param userVo
     */
    @Override
    public void addUser(UserVo userVo) {
        if (StringUtils.isEmpty(userVo)){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
        // 判断用户名是否唯一，只有用户名唯一在可以进行添加处理
        String userName = userVo.getUserName();
        QueryWrapper<User> queryWrapper =  new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);
        Long aLong = baseMapper.selectCount(queryWrapper);
        if (aLong >=1){
            // 管理员name已存在，不能进行添加处理
            throw new NovelGlobalException(ResultEnum.USER_NAME_IS_REGISTER.getCode(),ResultEnum.USER_NAME_IS_REGISTER.getMsg());
        }
        User user = new User();
        BeanUtils.copyProperties(userVo,user);
        user.setCreateTime(LocalDateTime.now());
        // 设置默认密码111111
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode("111111");
        user.setPassword(encode);
        // 添加管理员的时候，还要对sys_user_operatuin
        this.baseMapper.insert(user);
        // 添加之后就自增了id，可以获取到id了
        Integer userId = user.getUserId();
        // 以及sys_user_role表进行添加处理
        Integer[] roleIds = userVo.getRoleIds();
        if (roleIds != null){
            adminAddRole(userId,roleIds);     // 一个用户添加多个角色，一个用户添加多个菜单
        }else {
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }

    }

    // 根据id删除管理员，删除管理员的时候还要删除user_operation和user_role表
    @Override
    public void deleteById(Integer[] ids) {
        List<Integer> idList = Arrays.asList(ids);
        this.baseMapper.deleteBatchIds(idList);
        userOperationService.deleteByIds(idList);
        userRoleService.deleteByIds(idList);
    }

    /**
     * 根据adminId查询管理员
     * @param userId
     * @return
     */
    @Override
    public UserVo roleInfo(Integer userId) {
        if (StringUtils.isEmpty(userId)){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
        User user = this.baseMapper.selectById(userId);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);
        // 根据用户id，查询对应的角色然后显示在前端，List<Role>
        // 1、根据userId，查询出user_role集合
        List<UserRole> list = userRoleService.getRoleList(userId);
        List<Integer> roleList = list.stream().map(UserRole::getRoleId).collect(Collectors.toList());
        // 2、根据roleId可以查询到对应的role了
        if (ObjectUtils.isEmpty(roleList)){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
        //List<Role> roleList1 = roleService.getRolesList(roleList);
        List<Role> roleAll = roleService.getRoleAll();
        userVo.setRoleList(roleAll);
        return userVo;
    }

    /**
     * Admin的修改的处理
     * 需要进行用户名的唯一性处理
     * @param userVo
     */
    @Override
    public void updateRole(UserVo userVo) {
        User user = new User();
        // 查看user_name是否是唯一的，如果不是唯一的就不能进行修改处理
        if (!checkUserNameUnique(userVo)){
            throw new NovelGlobalException(410,"错误处理");
        }
        BeanUtils.copyProperties(userVo,user);
        user.setUpdateTime(LocalDateTime.now());
        Integer userId = userVo.getUserId();
        user.setUserId(userId);
        baseMapper.updateById(user);

        // 对user_operation以及user_role的处理过程
        Integer[] roleIds = userVo.getRoleIds();
        if (roleIds != null){
            adminAddRole(userId,roleIds);     // 一个用户添加多个角色，一个用户添加多个菜单
        }else {
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
    }

    /**
     * 判断用户是否允许操作
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(User user) {
        if (user.getUserId() ==1){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),"不允许操作管理员");
        }
    }


    @Override
    public void updateByUserId(User userById) {
        if (ObjectUtils.isEmpty(userById)){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
        this.baseMapper.updateById(userById);
    }


    /**
     * 判断Admin名称是否一致
     * @param userVo 页面修改传过来的信息
     * @return
     */
    public Boolean checkUserNameUnique(UserVo userVo){
        if (ObjectUtils.isEmpty(userVo)){
            throw new NovelGlobalException(ResultEnum.NOT_DATA.getCode(),ResultEnum.NOT_DATA.getMsg());
        }
        String userName = userVo.getUserName();
        Integer userId = userVo.getUserId();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);
        queryWrapper.last("limit 1");
        User user = baseMapper.selectOne(queryWrapper);
        // 他不是空，并且还有第二个数据，就表示不是唯一的
        if (!StringUtils.isEmpty(user) && userVo.getUserId() != userId){
            return false;
        }
        return true;      // 返回true，表示是唯一的
    }

    // 一个用户添加多个角色，一个用户添加多个菜单
    public void adminAddRole(Integer userId,Integer[] roleIds){
        UserRole userRole = new UserRole();
        UserOperation userOperation = new UserOperation();
        // 添加之前先把userId有关的role进行删除，然后在进行添加的处理
        QueryWrapper<UserRole> query = new QueryWrapper<>();
        query.eq("user_id",userId);
        userRoleService.remove(query);
        // 一个用户添加多个角色
        for (Integer roleId : roleIds) {
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            userRoleService.save(userRole);
            List<OperationRole> operationRoles = adminAddOperation(roleId, userId);  // 获取到菜单集合
            // 一个用户添加多个菜单
            for (OperationRole operationRole : operationRoles) {
                Integer operationId = operationRole.getOperationId();
                userOperation.setOperationId(operationId);   // 设置菜单id
                userOperation.setUserId(userId);
                // 多个角色，这里会有菜单的重复处理，所有在添加之前需要先进行查询操作
                QueryWrapper<UserOperation> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("user_id",userId).eq("operation_id",operationId);
                long count = userOperationService.count(queryWrapper);
                if (count == 0){                   // 数据库中没数据的时候在进行添加的处理
                    userOperationService.save(userOperation);
                }
            }
        }
    }

    // 根据角色id，查询角色对应菜单集合，然后进行添加处理
    public List<OperationRole> adminAddOperation(Integer roleId,Integer userId){
        // 根据角色id，查询出菜单List
        List<OperationRole> userOperations =  operationRoleService.getOperationList(roleId);
        return userOperations;
    }

}
